#pragma once

#include <iostream>
#include <sys/select.h>
#include "Socket.hpp"
#include "Log.hpp"
#include "InetAddr.hpp"

using namespace socket_ns;

class SelectServer
{
    // 总的文件描述符个数
    const static int gnum = sizeof(fd_set) * 8;
    const static int gdefaultfd = -1;

public:
    SelectServer(uint16_t port)
        : _port(port), _listensocket(std::make_unique<TcpSocket>()) // 匿名对象
    {
        _listensocket->BuildListenSocket(_port);
    }

    void InitServer()
    {
        for (int i = 0; i < gnum; ++i)
            fd_num[i] = gdefaultfd;
        fd_num[0] = _listensocket->Sockfd(); // 默认直接添加listen socket
    }

    void Loop()
    {
        while (true)
        {
            // fd_set初始化
            fd_set rfds;
            FD_ZERO(&rfds);
            int maxfd = gdefaultfd;

            // 设置fd_set
            for (int i = 0; i < gnum; ++i)
            {
                if (fd_num[i] == gdefaultfd)
                    continue;
                // 设置位图
                FD_SET(fd_num[i], &rfds);
                // 更新最大fd
                if (maxfd < fd_num[i])
                    maxfd = fd_num[i];
            }

            // 开始select 监听事件+派发事件
            struct timeval timeout = {10, 5};
            int n = ::select(maxfd + 1, &rfds, nullptr, nullptr, nullptr /* &timeout */);
            if (n > 0)
            {
                LOG(INFO, "haved event ready, n : %d\n", n); // 如果事件就绪，但是不处理，select会一直通知我，直到我处理了！
                HandlerEvent(rfds);
                PrintDebug();
                // sleep(1);
            }
            else if (n == 0)
                LOG(DEBUG, "time out, %d.%d\n", timeout.tv_sec, timeout.tv_usec);
            else
                LOG(ERROR, "select error\n");
        }
    }

    void HandlerEvent(fd_set &rfds) // 分为IO事件或者是listen事件
    {
        for (int i = 0; i < gnum; ++i)
        {
            if (fd_num[i] == gdefaultfd)
                continue;

            // 判断是否在位图中
            if (FD_ISSET(fd_num[i], &rfds))
            {
                if (fd_num[i] == _listensocket->Sockfd())
                    Accepter();
                else
                    HandlerIO(i); // 让IO处理获取下标
            }
        }
    }

    void Accepter()
    {
        InetAddr addr;
        int sockfd = _listensocket->Accepter(&addr);
        if (sockfd > 0)
        {
            LOG(DEBUG, "get a new link, client info %s:%d\n", addr.Ip().c_str(), addr.Port());

            bool flag = false;
            for (int pos = 0; pos < gnum; ++pos)
            {
                if (fd_num[pos] == gdefaultfd)
                {
                    fd_num[pos] = sockfd;
                    flag = true;
                    LOG(INFO, "add %d to fd_array success!\n", sockfd);
                    break;
                }
            }
            if (!flag)
            {
                LOG(WARNING, "Server Is Full!\n");
                ::close(sockfd);
            }
        }
    }

    // void HandlerIO(int i)
    // {
    //     char buffer[1024];
    //     ssize_t n = ::recv(fd_num[i], buffer, sizeof(buffer) - 1, 0);
    //     if (n > 0)
    //     {
    //         buffer[n] = 0;
    //         std::cout << "client say# " << buffer << std::endl;
    //         std::string content = "<html><body><h1>Hello lazy</h1></body></html>";
    //         std::string echo_str = "HTTP/1.0 200 OK\r\n";
    //         echo_str += "Content-Type: text/html\r\n";
    //         echo_str += "Content-Length: " + std::to_string(content.size()) + "\r\n\r\n";
    //         echo_str += content;
    //         // echo_str += buffer;
    //         ::send(fd_num[i], echo_str.c_str(), echo_str.size(), 0); // 临时方案
    //     }
    //     else if (n == 0)
    //     {
    //         LOG(INFO, "client quit...\n");
    //         // 关闭fd
    //         ::close(fd_num[i]);
    //         fd_num[i] = gdefaultfd;
    //     }
    //     else
    //     {
    //         LOG(INFO, "client quit...\n");
    //         // 关闭fd
    //         ::close(fd_num[i]);
    //         fd_num[i] = gdefaultfd;
    //     }
    // }

    void HandlerIO(int i)
    {
        char buffer[1024];
        ssize_t n = ::recv(fd_num[i], buffer, sizeof(buffer) - 1, 0);
        if (n > 0)
        {
            buffer[n] = 0;
            std::cout << "client say# " << buffer << std::endl;

            // 动态粒子爱心 + 文字动画
            std::string content = R"(
<html>
<head>
    <style>
        body {
            margin: 0;
            background: #000;
            overflow: hidden;
        }
        .text {
            position: absolute;
            top: 20%;
            left: 50%;
            transform: translateX(-50%);
            font-family: 'Segoe UI', sans-serif;
            font-size: 36px;
            color: #ffb6c1;
            text-shadow: 0 0 10px #fff, 0 0 20px #ff69b4;
            animation: glow 2s infinite ease-in-out;
        }
        @keyframes glow {
            0%, 100% { opacity: 0.8; }
            50% { opacity: 1; }
        }
    </style>
</head>
<body>
    <div class="text">❤️ 小祖宗早上好，我喜欢你~ ❤️</div>
    <canvas id="canvas"></canvas>
    <script>
        const canvas = document.getElementById('canvas');
        const ctx = canvas.getContext('2d');
        canvas.width = window.innerWidth;
        canvas.height = window.innerHeight;

        const particles = [];
        const particleCount = 400;

        function heartFunction(t) {
            const x = 16 * Math.pow(Math.sin(t), 3);
            const y = 13 * Math.cos(t) - 5 * Math.cos(2*t) - 2 * Math.cos(3*t) - Math.cos(4*t);
            return [x, -y];
        }

        for (let i = 0; i < particleCount; i++) {
            const t = Math.random() * Math.PI * 2;
            const [hx, hy] = heartFunction(t);
            particles.push({
                x: canvas.width/2,
                y: canvas.height/2,
                tx: canvas.width/2 + hx * 15,
                ty: canvas.height/2 + hy * 15,
                size: Math.random() * 2 + 1,
                color: `hsl(${Math.random() * 60 + 320}, 100%, 75%)`,
                life: 0,
                maxLife: 60 + Math.random() * 20
            });
        }

        function animate() {
            ctx.fillStyle = 'rgba(0, 0, 0, 0.1)';
            ctx.fillRect(0, 0, canvas.width, canvas.height);

            for (let p of particles) {
                p.life++;
                const progress = Math.min(p.life / p.maxLife, 1);
                const ease = 1 - Math.pow(1 - progress, 3);

                const x = p.x + (p.tx - p.x) * ease;
                const y = p.y + (p.ty - p.y) * ease;

                ctx.beginPath();
                ctx.arc(x, y, p.size, 0, Math.PI * 2);
                ctx.fillStyle = p.color;
                ctx.fill();
            }

            requestAnimationFrame(animate);
        }

        animate();
    </script>
</body>
</html>
)";

            // 构造HTTP响应
            std::string echo_str = "HTTP/1.1 200 OK\r\n";
            echo_str += "Content-Type: text/html; charset=utf-8\r\n";
            echo_str += "Connection: close\r\n";
            echo_str += "Content-Length: " + std::to_string(content.size()) + "\r\n\r\n";
            echo_str += content;

            ::send(fd_num[i], echo_str.c_str(), echo_str.size(), 0);
        }
        else if (n == 0)
        {
            LOG(INFO, "client quit...\n");
            ::close(fd_num[i]);
            fd_num[i] = gdefaultfd;
        }
        else
        {
            LOG(INFO, "client quit...\n");
            ::close(fd_num[i]);
            fd_num[i] = gdefaultfd;
        }
    }

    void PrintDebug()
    {
        std::cout << "fd list: ";
        for (int i = 0; i < gnum; i++)
        {
            if (fd_num[i] == gdefaultfd)
                continue;
            std::cout << fd_num[i] << " ";
        }
        std::cout << "\n";
    }

private:
    uint16_t _port;
    std::unique_ptr<Socket> _listensocket;

    int fd_num[gnum]; // 辅助数组
};